package grape.attend.service.user.impl;

import cn.hutool.core.date.*;
import grape.attend.service.classe.api.IClasseService;
import grape.attend.service.classe.po.Classe;
import grape.attend.service.clock.api.IClockService;
import grape.attend.service.clock.po.Clock;
import grape.attend.service.group.api.IGroupClasseRelService;
import grape.attend.service.group.api.IGroupService;
import grape.attend.service.group.po.Group;
import grape.attend.service.overtime.api.IOvertimeLegalService;
import grape.attend.service.overtime.api.IOvertimeRestService;
import grape.attend.service.overtime.api.IOvertimeService;
import grape.attend.service.overtime.api.IOvertimeWorkService;
import grape.attend.service.overtime.dto.OvertimeConfig;
import grape.attend.service.overtime.po.Overtime;
import grape.attend.service.overtime.po.OvertimeLegal;
import grape.attend.service.overtime.po.OvertimeRest;
import grape.attend.service.overtime.po.OvertimeWork;
import grape.attend.service.overtime.servicemapper.OvertimeConfigServiceMapper;
import grape.attend.service.user.api.*;
import grape.attend.service.user.clock.PreClockParam;
import grape.attend.service.user.clock.UserClockOffClockService;
import grape.attend.service.user.clock.UserClockOnClockService;
import grape.attend.service.user.dto.GroupAndClasseDto;
import grape.attend.service.user.po.*;
import grape.attend.service.user.mapper.UserClockMapper;
import grape.attend.service.vacation.api.IVacationService;
import grape.attend.service.vacation.po.Vacation;
import grape.base.rest.client.dict.DictClient;
import grape.composite.rest.client.workcalendar.WorkCalendarClient;
import grape.base.service.dict.po.Dict;
import grape.composite.service.workcalendar.po.WorkCalendar;
import grape.common.exception.runtime.InvalidParamsException;
import grape.common.exception.runtime.RBaseException;
import grape.common.service.common.BaseServiceImpl;
import grape.common.tools.calendar.CalendarUtils;
import grape.common.tools.calendar.LunarCalendarUtils;
import grape.common.tools.calendar.LunarDate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Optional;

/**
 * <p>
 * 用户打卡表 服务实现类
 * </p>
 *
 * @author yangwei
 * @since 2020-05-18
 */
@Slf4j
@Service
public class UserClockServiceImpl extends BaseServiceImpl<UserClockMapper, UserClock> implements IUserClockService {

    @Autowired
    private IClasseService iClasseService;
    @Autowired
    private IGroupService iGroupService;
    @Autowired
    private IClockService iClockService;
    @Autowired
    private DictClient dictClient;
    @Autowired
    private IGroupClasseRelService iGroupClasseRelService;
    @Autowired
    private IOvertimeService iOvertimeService;
    @Autowired
    private IUserClockDateService iUserClockDateService;
    @Autowired
    private IUserClockDateClasseService iUserClockDateClasseService;
    @Autowired
    private IUserOvertimeService iUserOvertimeService;
    @Autowired
    private WorkCalendarClient workCalendarClient;
    @Autowired
    private UserClockOnClockService userClockOnClockService;
    @Autowired
    private UserClockOffClockService userClockOffClockService;

    @Autowired
    private IOvertimeLegalService iOvertimeLegalService;

    @Autowired
    private IOvertimeRestService iOvertimeRestService;

    @Autowired
    private IOvertimeWorkService iOvertimeWorkService;
    @Autowired
    private OvertimeConfigServiceMapper overtimeConfigServiceMapper;
    @Autowired
    private IVacationService iVacationService;
    @Autowired
    private IUserVacationSumRecordService iUserVacationSumRecordService;
    @Autowired
    private IUserVacationSumService iUserVacationSumService;

    @Override
    public UserClock onClock(UserClock userClock,Boolean isClasseYestoday,String userId) {
        PreClockParam preClockParam = preClock(userClock, isClasseYestoday, userId, true);
        // 默认先设置为不迟到
        userClock.setIsOnClockLate(false);

        userClock.setOnClockAt(preClockParam.getNow());
        if (isEqual(Clock.TypeDict.normal_clock.name(),preClockParam.getClockTypeDict().getCode())) {
            userClockOnClockService.normalClock(preClockParam, userClock);
        }
        // 早到早走晚到晚走
        else if (isEqual(Clock.TypeDict.allow_earl_early_late_late.name(),preClockParam.getClockTypeDict().getCode())) {
            userClockOnClockService.allowEarlEarlyLateLate(preClockParam, userClock);
        }
        // 可以早走晚到几分钟
        else if (isEqual(Clock.TypeDict.allow_earl_late.name(),preClockParam.getClockTypeDict().getCode())) {
            userClockOnClockService.allowEarlLate(preClockParam, userClock);
        }
        else {
            throw new RBaseException("不支持的打卡设置");
        }

        // 如果有异常，更新班次异常
        if(userClock.getIsOnClockLate()){
            iUserClockDateService.updateHasErrorField(preClockParam.getUserClockDate().getId(), true);
        }
        return insert(userClock);
    }

    @Override
    public UserClock offClock(UserClock userClock,Boolean isClasseYestoday,String userId) {
        PreClockParam preClockParam = preClock(userClock, isClasseYestoday, userId, false);
        // 默认先设置为不迟到
        userClock.setIsOffClockLeaveEarly(false);
        userClock.setOffClockAt(preClockParam.getNow());
        if (isEqual(Clock.TypeDict.normal_clock.name(),preClockParam.getClockTypeDict().getCode())) {
            userClockOffClockService.normalClock(preClockParam, userClock);
        }
        // 早到早走晚到晚走
        else if (isEqual(Clock.TypeDict.allow_earl_early_late_late.name(),preClockParam.getClockTypeDict().getCode())) {
            userClockOffClockService.allowEarlEarlyLateLate(preClockParam, userClock);
        }
        // 可以早走晚到几分钟
        else if (isEqual(Clock.TypeDict.allow_earl_late.name(),preClockParam.getClockTypeDict().getCode())) {
            userClockOffClockService.allowEarlLate(preClockParam, userClock);
        }
        else {
            throw new RBaseException("不支持的打卡设置");
        }
        if (isStrEmpty(userClock.getId())) {
            userClock = insert(userClock);
        }else{
            boolean r = updateById(userClock);
            if (r) {
                userClock = getById(userClock.getId());
            }else {
                throw new RBaseException("更新打卡失败，可能数据不存在");
            }
        }

        // 如果下班打卡正常，计算加班
        if (userClock.getIsOffClockLeaveEarly() == false &&  !preClockParam.getClock().getIsNextDayLate()) {
            saveOvertimeIsNecessary(preClockParam,userClock);
        }
        if(userClock.getIsOffClockLeaveEarly()){
            iUserClockDateService.updateHasErrorField(preClockParam.getUserClockDate().getId(), true);
        }
        return userClock;
    }

    @Override
    public String[] getDefaultLegal(Date classeDate) {
        String[] defaultLunarLegal = Arrays.copyOf(WorkCalendar.defaultLunarLegal, WorkCalendar.defaultLunarLegal.length);
        // 将阴历转阳历
        for (int i = 0; i < defaultLunarLegal.length; i++) {
            String md[] = defaultLunarLegal[i].split("-");
            Date date = LunarCalendarUtils.LunarToCalendar(new LunarDate(
                    DateUtil.year(classeDate),
                    Integer.parseInt(md[0]),
                    Integer.parseInt(md[1]),
                    DateUtil.hour(classeDate, true),
                    DateUtil.minute(classeDate),
                    DateUtil.second(classeDate)
            ));
            defaultLunarLegal[i] = DateUtil.format(date, CalendarUtils.DateStyle.MM_DD.getValue());
        }
        String result[] = Arrays.copyOf(WorkCalendar.defaultLegal, WorkCalendar.defaultLegal.length + WorkCalendar.defaultLunarLegal.length);
        for (int i = 0; i < defaultLunarLegal.length; i++) {
            result[WorkCalendar.defaultLegal.length + i] = defaultLunarLegal[i];
        }
        return result;
    }
    /**
     * 上下班打卡前置公共方法
     * @param userClock
     * @param isClasseYestoday
     * @param userId
     * @param isOnClock true=上班打卡，false=下班打卡
     * @return
     */
    private PreClockParam preClock(UserClock userClock,Boolean isClasseYestoday,String userId,boolean isOnClock){
        assertParamNotEmpty(userClock.getGroupId(),"groupId 不能为空");
        assertParamNotEmpty(userClock.getClasseId(),"classeId 不能为空");
        // 应该是当前登录用户的id
        assertParamNotEmpty(userId,"userId 不能为空");

        // 检查groupId和classeId是否匹配
        Classe classe = iClasseService.getByGroupIdAndClasseId(userClock.getGroupId(), userClock.getClasseId());
        if (classe == null) {
            throw new InvalidParamsException("groupId和classeId的值不匹配");
        }
        // 班次日期
        Date classeDate = new Date();
        if (isClasseYestoday) {
            classeDate = DateUtil.yesterday();
        }
        String classeDateStr = DateUtil.formatDate(classeDate);
        // 班次日期记录
        UserClockDate userClockDate = iUserClockDateService.addUserClockDateIfNecessary(classeDate, userId);
        // 班次日期所有班次记录
        iUserClockDateClasseService.addUserClockDateClassesIfNecessary(userClockDate.getId(), userId);
        // 设置班次日期
        userClock.setUserClockDateId(userClockDate.getId());
        // 上班打卡不能重复打
        UserClock dbUserClock = getClock(userClock.getGroupId(),userClock.getClasseId(),userId,classeDate);
        if (dbUserClock != null) {
            if(isOnClock){
                throw new InvalidParamsException("该班次已经打过上班卡，不能重复打卡");
            }else {
                userClock.setId(dbUserClock.getId());
            }
        }


        Group group = iGroupService.getById(userClock.getGroupId());


        List<GroupAndClasseDto> classeDtoList = iGroupClasseRelService.getGroupAndClasseCurrentByUserId(userId);
        GroupAndClasseDto nextGroupAndClasse = iGroupClasseRelService.getNextGroupAndClasse(group, classe, classeDtoList);
        GroupAndClasseDto preGroupAndClasse = iGroupClasseRelService.getPreGroupAndClasse(group, classe, classeDtoList);


        if (isOnClock && !IUserClockService.isAllowOnClock(group,classe,nextGroupAndClasse.getClasse(),nextGroupAndClasse.getGroup(),dbUserClock,isClasseYestoday)) {
            throw new InvalidParamsException("该班次当前时间禁止打卡");
        }
        if (!isOnClock && !IUserClockService.isAllowOffClock(group,classe,nextGroupAndClasse.getClasse(),nextGroupAndClasse.getGroup(),dbUserClock,isClasseYestoday)) {
            throw new InvalidParamsException("该班次当前时间禁止打卡");
        }
        // 考勤组对应的打卡设置
        Clock clock = iClockService.getById(Optional.ofNullable(classe.getClockId()).orElse(group.getClockId()));
        Dict clockTypeDict = dictClient.getDictById(clock.getTypeDictId());

        // 当前毫秒数
        long now = DateUtil.current(false);

        // classeDateStr 格式为yyyy-MM-dd
        // classe.getStartTime() 目前格式为 HH:mm
        long startTime = DateUtil.parseDateTime(classeDateStr + " " +classe.getStartTime() + ":00").getTime();
        // classe.getEndTime() 目前格式为 HH:mm
        long endTime = DateUtil.parseDateTime(classeDateStr + " " +classe.getEndTime() + ":00").getTime();


        Long restStartTime = null;
        Long restEndTime = null;
        if (classe.getIsHasRest()) {
            restStartTime = DateUtil.parseDateTime(classeDateStr + " " +classe.getRestStartTime() + ":00").getTime();
            restEndTime = DateUtil.parseDateTime(classeDateStr + " " +classe.getRestEndTime() + ":00").getTime();
            if(restEndTime < restStartTime){
                restEndTime += DateUnit.DAY.getMillis();
            }
        }

        boolean isClasseCrossDay = false;
        if(endTime < startTime){
            endTime += DateUnit.DAY.getMillis();
            isClasseCrossDay = true;
        }

        int classeDateYear = DateUtil.year(classeDate);
        int classeDateMonth = (DateUtil.month(classeDate) + 1);
        int classeDateDay = DateUtil.dayOfMonth(classeDate);

        List<WorkCalendar> workCalendars = workCalendarClient.list(classeDateYear,classeDateMonth,classeDateDay,null,null);

        UserClock userClockPre = null;
        // 判断是否打卡设置了开启下班晚走，下一个班次可以晚到
        if(clock.getIsNextDayLate()){
            // 查询上一个班次的打卡
            // 如果上一个班次和当前班次相同，则取前一日的打卡，如果不同则取当前打卡班次日期的打卡

            Date preUserClockClassDate = classeDate;
            if(isEqual(preGroupAndClasse.getClasse().getId(),classe.getId())){
                preUserClockClassDate = DateUtil.offsetDay(classeDate, -1);
            }else{
            }
            userClockPre = getClock(preGroupAndClasse.getGroup().getId(), preGroupAndClasse.getClasse().getId(), userId, preUserClockClassDate);
        }

        PreClockParam preClockParam = new PreClockParam();

        preClockParam.setGroup(group);
        preClockParam.setClasse(classe);
        preClockParam.setClasseDate(classeDate);
        preClockParam.setUserClockDate(userClockDate);
        preClockParam.setDbUserClock(dbUserClock);
        preClockParam.setPreUserClock(userClockPre);
        preClockParam.setNextGroupAndClasse(nextGroupAndClasse);
        preClockParam.setPreGroupAndClasse(preGroupAndClasse);
        preClockParam.setClock(clock);
        preClockParam.setNow(now);
        preClockParam.setClasseStartAt(startTime);
        preClockParam.setClasseEndAt(endTime);
        preClockParam.setClasseRestStartAt(restStartTime);
        preClockParam.setClasseRestEndAt(restEndTime);
        preClockParam.setIsClasseCrossDay(isClasseCrossDay);
        preClockParam.setClockTypeDict(clockTypeDict);
        if (!isEmpty(workCalendars)) {
            Dict legalDict = dictClient.getDictByCode(WorkCalendar.DateType.date_type_legal.name());
            Dict restDict = dictClient.getDictByCode(WorkCalendar.DateType.date_type_rest.name());
            Dict workDict = dictClient.getDictByCode(WorkCalendar.DateType.date_type_work.name());
            for (WorkCalendar workCalendar : workCalendars) {
                if (isEqual(workCalendar.getDateTypeDictId(),legalDict.getId())) {
                    preClockParam.setClasseDatewWorkCalendar(workCalendar);
                    preClockParam.setClasseDateDateType(WorkCalendar.DateType.date_type_legal);
                }else if (isEqual(workCalendar.getDateTypeDictId(),restDict.getId())) {
                    preClockParam.setClasseDatewWorkCalendar(workCalendar);
                    preClockParam.setClasseDateDateType(WorkCalendar.DateType.date_type_rest);
                }else if (isEqual(workCalendar.getDateTypeDictId(),workDict.getId())) {
                    preClockParam.setClasseDatewWorkCalendar(workCalendar);
                    preClockParam.setClasseDateDateType(WorkCalendar.DateType.date_type_work);
                }
            }
            if (preClockParam.getClasseDatewWorkCalendar() != null && !isStrEmpty(preClockParam.getClasseDatewWorkCalendar().getTypeDictId())) {
                Dict typeDict = dictClient.getDictById(preClockParam.getClasseDatewWorkCalendar().getTypeDictId());
                for (WorkCalendar.Type value : WorkCalendar.Type.values()) {
                    if (isEqual(value.name(),typeDict.getCode())) {
                        preClockParam.setClasseDateType(value);
                    }
                }
            }
        }
        // 法定节假日
        if(preClockParam.getClasseDateDateType() == null){
            String defaultLegal[] = getDefaultLegal(classeDate);
            if (defaultLegal != null) {
                String classeDateMd = DateUtil.format(classeDate, CalendarUtils.DateStyle.MM_DD.getValue());
                for (int i = 0; i < defaultLegal.length; i++) {
                    if (isEqual(classeDateMd,defaultLegal[i])) {
                        preClockParam.setClasseDateDateType(WorkCalendar.DateType.date_type_legal);
                    }
                }
            }
        }
        // 休息日
        if(preClockParam.getClasseDateDateType() == null){
            Week week = DateUtil.dayOfWeekEnum(classeDate);
            if (week.getValue() == Week.SUNDAY.getValue() || week.getValue() == Week.SATURDAY.getValue()) {
                preClockParam.setClasseDateDateType(WorkCalendar.DateType.date_type_rest);
            }else {
                preClockParam.setClasseDateDateType(WorkCalendar.DateType.date_type_work);
            }
        }
        return preClockParam;
    }


    @Override
    public UserClock getClock(String groupId, String classeId, String userId, Date classeDate) {
        assertParamNotEmpty(groupId,"groupId 不能为空");
        assertParamNotEmpty(classeId,"classeId 不能为空");
        // 应该是当前登录用户的id
        assertParamNotEmpty(userId,"userId 不能为空");
        assertParamNotNull(classeDate,"clockDate 不能为空");

        UserClockDate userClockDate = iUserClockDateService.getByClasseDateAndUserId(classeDate, userId);
        if (userClockDate == null) {
            return null;
        }
        UserClock userClockDbCondition = new UserClock();
        userClockDbCondition.setGroupId(groupId);
        userClockDbCondition.setClasseId(classeId);
        userClockDbCondition.setUserClockDateId(userClockDate.getId());
        return getOne(userClockDbCondition);
    }

    @Override
    public void onUserOvertime(UserOvertime userOvertime,UserOvertime dbUserOvertime) {

        // 添加用户调休假期余额
        Vacation vacation = iVacationService.getByCode(Vacation.VacationCode.vacation_leave.name());
        if (vacation != null) {
            // 用户的假期余额
            UserVacationSum userVacationSum = iUserVacationSumService.getByUserIdAndVacationId(userOvertime.getUserId(), vacation.getId());
            if (userVacationSum == null) {
                userVacationSum = new UserVacationSum();
                userVacationSum.setUserId(userOvertime.getUserId());
                userVacationSum.setVacationId(vacation.getId());
                userVacationSum.setLeaveSum(!userOvertime.getIsApprove() ? userOvertime.getOvertime() : 0);
                userVacationSum = iUserVacationSumService.insert(userVacationSum);
            }else {
                // 不需要审批直接加
                if (!userOvertime.getIsApprove()) {
                    userVacationSum.setLeaveSum(userOvertime.getOvertime() + userVacationSum.getLeaveSum());
                    // 如果db中的存在，说明下班打卡打了多次，假期余额得减去上一次的已经添加的加班
                    if (dbUserOvertime != null) {
                        userVacationSum.setLeaveSum(userVacationSum.getLeaveSum() - dbUserOvertime.getOvertime());

                    }
                    iUserVacationSumService.updateById(userVacationSum);
                }

            }

            Dict dict = dictClient.getDictByCode(UserVacationSumRecord.DictVacationSumChangeType.overtime.name());
            UserVacationSumRecord dbUserVacationSumRecord = iUserVacationSumRecordService.getOne(userOvertime.getUserId(), dict.getId(), userVacationSum.getId(), userOvertime.getId());
            if (dbUserVacationSumRecord == null) {
                UserVacationSumRecord userVacationSumRecord = new UserVacationSumRecord();
                userVacationSumRecord.setIsVacationSumPlus(true);
                userVacationSumRecord.setTypeDictId(dict.getId());
                userVacationSumRecord.setUserId(userOvertime.getUserId());
                userVacationSumRecord.setVacationSum(userOvertime.getOvertime());
                userVacationSumRecord.setUserVacationId(userVacationSum.getId());
                iUserVacationSumRecordService.insert(userVacationSumRecord);
            }else {
                dbUserVacationSumRecord.setVacationSum(userOvertime.getOvertime());
                iUserVacationSumRecordService.updateById(dbUserVacationSumRecord);
            }

        }else {
            log.warn("未配置编码为{}的调休假",Vacation.VacationCode.vacation_leave.name());
        }

    }

    /**
     * 添加加班数据，下班打卡调用
     * @param preClockParam
     * @param offClock
     */
    private void saveOvertimeIsNecessary(PreClockParam preClockParam,UserClock offClock) {

        assertNotNull(offClock,"offClock 不能为空");

        // 下班晚走，第二天可以晚到不计加班
        if (preClockParam.getClock().getIsNextDayLate()) {
            return;
        }

        // 加班配置
        Overtime overtime = iOvertimeService.getById(preClockParam.getGroup().getOvertimeId());


        OvertimeConfig overtimeConfig = null;

        // 工作日
        if(preClockParam.getClasseDateDateType().name().equals(WorkCalendar.DateType.date_type_work.name())){
            // 工作日加班配置
            OvertimeWork overtimeWork = iOvertimeWorkService.getById(overtime.getOvertimeWorkId());
            overtimeConfig = overtimeConfigServiceMapper.toOvertimeConfig(overtimeWork);
        }
        // 休息日
        else if(preClockParam.getClasseDateDateType().name().equals(WorkCalendar.DateType.date_type_rest.name())){
            // 休息日加班配置
            OvertimeRest overtimeRest = iOvertimeRestService.getById(overtime.getOvertimeRestId());
            overtimeConfig = overtimeConfigServiceMapper.toOvertimeConfig(overtimeRest);


        }
        // 法定节假日
        else if(preClockParam.getClasseDateDateType().name().equals(WorkCalendar.DateType.date_type_legal.name())){

            // 节假日加班配置
            OvertimeLegal overtimeLegal = iOvertimeLegalService.getById(overtime.getOvertimeLegalId());
            overtimeConfig = overtimeConfigServiceMapper.toOvertimeConfig(overtimeLegal);
        }
        UserOvertime userOvertime = null;
        if (overtimeConfig.getIsAllowOvertime()) {
            // 如果班次日期设置了
            if (preClockParam.getClasseDatewWorkCalendar() != null) {
                // 设置了全天休息，全天加班
                if (preClockParam.getClasseDateType().name().equals(WorkCalendar.Type.all_day_rest.name())) {
                    userOvertime = userOvertimeAllDayRest(preClockParam, offClock,overtimeConfig);
                }
                // 设置了上午休息，上午早到，不计加班
                else  if (preClockParam.getClasseDateType().name().equals(WorkCalendar.Type.day_am_rest_pm_work.name())) {
                    userOvertime = userOvertimeAmRestPmWork(preClockParam, offClock,overtimeConfig);
                }
                // 设置了下午休息，计加班，
                else  if (preClockParam.getClasseDateType().name().equals(WorkCalendar.Type.day_am_work_pm_rest.name())) {
                    userOvertime = userOvertimeAmWorkPmRest(preClockParam, offClock,overtimeConfig);
                }
                // 全天上班，计加班
                else  if (preClockParam.getClasseDateType().name().equals(WorkCalendar.Type.all_day_work.name())) {
                    userOvertime = userOvertimeAllDayWork(preClockParam, offClock,overtimeConfig);
                }
            }else {
                // 如果班次日期没有设置，那么按默认的自然日
                // 全天上班，计加班
                if(preClockParam.getClasseDateDateType().name().equals(WorkCalendar.DateType.date_type_work.name())){
                    userOvertime = userOvertimeAllDayWork(preClockParam, offClock,overtimeConfig);
                }
                // 全天加班
                else if(preClockParam.getClasseDateDateType().name().equals(WorkCalendar.DateType.date_type_rest.name())){
                    userOvertime = userOvertimeAllDayRest(preClockParam, offClock,overtimeConfig);
                }
                // 全天加班
                else if(preClockParam.getClasseDateDateType().name().equals(WorkCalendar.DateType.date_type_legal.name())){
                    userOvertime = userOvertimeAllDayRest(preClockParam, offClock,overtimeConfig);
                }
            }
            if (userOvertime != null) {
                userOvertime.setIsEffect(!overtimeConfig.getIsApprove());
                userOvertime.setIsApprove(overtimeConfig.getIsApprove());
                userOvertime.setUserClockId(offClock.getId());
                userOvertime.setUserId(preClockParam.getUserClockDate().getUserId());
                userOvertime.setClasseDate(preClockParam.getClasseDate());
                // 合理化步长
                if (overtimeConfig.getStep() != null) {
                    userOvertime.setOvertime((userOvertime.getOvertime() / overtimeConfig.getStep()) * overtimeConfig.getStep());
                }
                // 加班时长合理化
                if (overtimeConfig.getAtLeast() != null && overtimeConfig.getAtLeast()  >userOvertime.getOvertime()) {
                    // 不够最小时长，不计加班
                    return;
                }

                if (overtimeConfig.getAtMost() != null && overtimeConfig.getAtMost() < userOvertime.getOvertime()) {
                    userOvertime.setOvertime(overtimeConfig.getAtMost());
                }
                if (overtimeConfig.getTimes() != null && overtimeConfig.getTimes() > 0) {
                    userOvertime.setOvertime(userOvertime.getOvertime() * overtimeConfig.getTimes());
                }
                // 如果需要审批，添加审批状态为未提交
                if (overtimeConfig.getIsApprove()) {
                    Dict dict = dictClient.getDictByCode(UserOvertime.DictApproveStatus.user_overtime_approve_status_unsubmit.name());
                    userOvertime.setApproveStatusDictId(dict.getId());
                }
            }

            if (userOvertime != null) {
                UserOvertime dbUserOvertime = iUserOvertimeService.getByUserIdAndUserClockId(userOvertime.getUserId(), userOvertime.getUserClockId());
                if (dbUserOvertime == null) {
                    // 添加加班数据
                    userOvertime = iUserOvertimeService.insert(userOvertime);
                }else {
                    userOvertime.setId(dbUserOvertime.getId());
                    iUserOvertimeService.updateById(userOvertime);
                }

                // 处理加班后的事宜
                onUserOvertime(userOvertime,dbUserOvertime);
            }
        }

    }

    /**
     * 全天休息加班计算
     * @param preClockParam
     * @param offClock
     * @param overtimeConfig
     * @return 不符合加班条件，返回null
     */
    private UserOvertime userOvertimeAllDayRest(PreClockParam preClockParam,UserClock offClock,OvertimeConfig overtimeConfig){
        UserOvertime overtime = null;
        // 如果上班没有打卡算不了加班
        if (offClock.getOnClockAt() != null) {
            Long start = null;
            Long end = null;
            int deductRestTime = 0;
            // 全部包括休息时间
            // 每个区间对应的数字
            //    |_____________|__|____________|__|
            //  1       2         3      4        5   6
            if(preClockParam.getClasse().getIsHasRest() && overtimeConfig.getIsDeductRestTime()){
                // 1
                if (offClock.getOnClockAt() <= preClockParam.getClasseStartAt()) {
                    start = preClockParam.getClasseStartAt();
                    // 1
                    if(offClock.getOffClockAt() < preClockParam.getClasseRestStartAt()){
                    }
                    // 2
                    else if(offClock.getOffClockAt() < preClockParam.getClasseRestEndAt()){
                        end = preClockParam.getClasseRestStartAt();
                    }
                    // 3
                    else if(offClock.getOffClockAt() < preClockParam.getClasseRestEndAt()){
                        end = preClockParam.getClasseRestStartAt();
                    }
                    // 4
                    else if(offClock.getOffClockAt() < preClockParam.getClasseEndAt()){
                        end = offClock.getOffClockAt();
                        deductRestTime = IUserClockService.getIntervalMinutes(preClockParam.getClasseRestEndAt(), preClockParam.getClasseRestStartAt());
                    }
                    // 5
                    else if(offClock.getOffClockAt() < preClockParam.getClasseEndAt() + overtimeConfig.getRestTime()* DateUnit.MINUTE.getMillis()){
                        end = preClockParam.getClasseEndAt();
                        deductRestTime = IUserClockService.getIntervalMinutes(preClockParam.getClasseRestEndAt(), preClockParam.getClasseRestStartAt());
                    }
                    // 6
                    else {
                        end = offClock.getOffClockAt();
                        deductRestTime = IUserClockService.getIntervalMinutes(preClockParam.getClasseRestEndAt(), preClockParam.getClasseRestStartAt()) + overtimeConfig.getRestTime();
                    }
                }
                // 2
                else if (offClock.getOnClockAt() < preClockParam.getClasseRestStartAt()) {
                    start = offClock.getOnClockAt();
                    // 2
                    if(offClock.getOffClockAt() < preClockParam.getClasseRestStartAt()){
                        end = offClock.getOffClockAt();
                    }
                    // 3
                    else if(offClock.getOffClockAt() < preClockParam.getClasseRestEndAt()){
                        end = preClockParam.getClasseRestStartAt();
                    }
                    // 4
                    else if(offClock.getOffClockAt() < preClockParam.getClasseEndAt()){
                        end = offClock.getOffClockAt();
                        deductRestTime = IUserClockService.getIntervalMinutes(preClockParam.getClasseRestEndAt(), preClockParam.getClasseRestStartAt());
                    }
                    // 5
                    else if(offClock.getOffClockAt() < preClockParam.getClasseEndAt() + overtimeConfig.getRestTime()* DateUnit.MINUTE.getMillis()){
                        end = preClockParam.getClasseEndAt();
                        deductRestTime = IUserClockService.getIntervalMinutes(preClockParam.getClasseRestEndAt(), preClockParam.getClasseRestStartAt());
                    }
                    // 6
                    else {
                        end = offClock.getOffClockAt();
                        deductRestTime = IUserClockService.getIntervalMinutes(preClockParam.getClasseRestEndAt(), preClockParam.getClasseRestStartAt()) + overtimeConfig.getRestTime();
                    }
                }
                // 3
                else if (offClock.getOnClockAt() < preClockParam.getClasseRestEndAt()) {
                    start = preClockParam.getClasseRestEndAt();
                    // 3
                    if(offClock.getOffClockAt() < preClockParam.getClasseRestEndAt()){
                    }
                    // 4
                    else if(offClock.getOffClockAt() < preClockParam.getClasseEndAt()){
                        end = offClock.getOffClockAt();
                    }
                    // 5
                    else if(offClock.getOffClockAt() < preClockParam.getClasseEndAt() + overtimeConfig.getRestTime()* DateUnit.MINUTE.getMillis()){
                        end = preClockParam.getClasseEndAt();
                    }
                    // 6
                    else {
                        end = offClock.getOffClockAt();
                        deductRestTime = overtimeConfig.getRestTime();
                    }
                }
                // 4
                else if (offClock.getOnClockAt() < preClockParam.getClasseEndAt()) {
                    start = offClock.getOnClockAt();
                    // 4
                    if(offClock.getOffClockAt() < preClockParam.getClasseEndAt()){
                        end = offClock.getOffClockAt();
                    }
                    // 5
                    else if(offClock.getOffClockAt() < preClockParam.getClasseEndAt() + overtimeConfig.getRestTime()* DateUnit.MINUTE.getMillis()){
                        end = preClockParam.getClasseEndAt();
                    }
                    // 6
                    else {
                        end = offClock.getOffClockAt();
                        deductRestTime = overtimeConfig.getRestTime();
                    }
                }
                // 5
                else if (offClock.getOnClockAt() < preClockParam.getClasseEndAt() + overtimeConfig.getRestTime() * DateUnit.MINUTE.getMillis()) {
                    start = preClockParam.getClasseEndAt() + overtimeConfig.getRestTime() * DateUnit.MINUTE.getMillis();
                    // 6
                    if(offClock.getOffClockAt() > preClockParam.getClasseEndAt() + overtimeConfig.getRestTime()* DateUnit.MINUTE.getMillis()){
                        end = offClock.getOffClockAt();
                        deductRestTime = overtimeConfig.getRestTime();
                    }
                }
                // 6
                else {
                    start = offClock.getOnClockAt();
                    // 6
                    end = offClock.getOffClockAt();
                }
            }
            // 班次休息，下班之后不休息
            // 每个区间对应的数字
            //    |_____________|__|____________|
            //  1       2         3      4        5
            else if(preClockParam.getClasse().getIsHasRest() && !overtimeConfig.getIsDeductRestTime()){
                // 1
                if (offClock.getOnClockAt() <= preClockParam.getClasseStartAt()) {
                    start = preClockParam.getClasseStartAt();
                    // 1
                    if(offClock.getOffClockAt() < preClockParam.getClasseStartAt()){
                    }
                    // 2
                    else if(offClock.getOffClockAt() < preClockParam.getClasseRestStartAt()){
                        end = offClock.getOffClockAt();
                    }
                    // 3
                    else if(offClock.getOffClockAt() < preClockParam.getClasseRestEndAt()){
                        end = preClockParam.getClasseRestStartAt();
                    }
                    // 4 5
                    else {
                        end = offClock.getOffClockAt();
                        deductRestTime = IUserClockService.getIntervalMinutes(preClockParam.getClasseRestEndAt(), preClockParam.getClasseRestStartAt());
                    }
                }
                // 2
                else if (offClock.getOnClockAt() < preClockParam.getClasseRestStartAt()) {
                    start = offClock.getOnClockAt();
                    // 2
                    if(offClock.getOffClockAt() < preClockParam.getClasseRestStartAt()){
                        end = offClock.getOffClockAt();
                    }
                    // 3
                    else if(offClock.getOffClockAt() < preClockParam.getClasseRestEndAt()){
                        end = preClockParam.getClasseRestStartAt();
                    }
                    // 4 5
                    else if(offClock.getOffClockAt() < preClockParam.getClasseEndAt()){
                        end = offClock.getOffClockAt();
                        deductRestTime = IUserClockService.getIntervalMinutes(preClockParam.getClasseRestEndAt(), preClockParam.getClasseRestStartAt());
                    }
                }
                // 3
                else if (offClock.getOnClockAt() < preClockParam.getClasseRestEndAt()) {
                    start = preClockParam.getClasseRestEndAt();
                    // 4 5
                    if(offClock.getOffClockAt() > preClockParam.getClasseRestEndAt()){
                        end = offClock.getOffClockAt();
                    }
                }
                // 4 5
                else {
                    start = offClock.getOnClockAt();
                    // 5 6
                    end = offClock.getOffClockAt();
                }
            }
            // 班次不休息，下班之后休息
            // 每个区间对应的数字
            //    |_________________________|__|
            //  1              2             3      4
            else if(!preClockParam.getClasse().getIsHasRest() && overtimeConfig.getIsDeductRestTime()){
                // 1
                if (offClock.getOnClockAt() <= preClockParam.getClasseStartAt()) {
                    start = preClockParam.getClasseStartAt();
                    // 1
                    if(offClock.getOffClockAt() < preClockParam.getClasseStartAt()){

                    }
                    // 2
                    else if(offClock.getOffClockAt() < preClockParam.getClasseEndAt()){
                        end = offClock.getOffClockAt();
                    }
                    // 3
                    else if(offClock.getOffClockAt() < preClockParam.getClasseEndAt() + overtimeConfig.getRestTime() * DateUnit.MINUTE.getMillis()){
                        end = preClockParam.getClasseEndAt();
                    }
                    // 4
                    else {
                        end = offClock.getOffClockAt();
                        deductRestTime = overtimeConfig.getRestTime();
                    }
                }
                // 2
                else if (offClock.getOnClockAt() <= preClockParam.getClasseEndAt()) {
                    start = offClock.getOnClockAt();
                    // 2
                    if(offClock.getOffClockAt() < preClockParam.getClasseEndAt()){
                        end = offClock.getOffClockAt();
                    }
                    // 3
                    else if(offClock.getOffClockAt() < preClockParam.getClasseEndAt() + overtimeConfig.getRestTime() * DateUnit.MINUTE.getMillis()){
                        end = preClockParam.getClasseEndAt();
                    }
                    // 4
                    else {
                        end = offClock.getOffClockAt();
                        deductRestTime = overtimeConfig.getRestTime();
                    }
                }
                // 3
                else if (offClock.getOnClockAt() <= preClockParam.getClasseEndAt() + overtimeConfig.getRestTime()* DateUnit.MINUTE.getMillis() ) {
                    start = preClockParam.getClasseEndAt() + overtimeConfig.getRestTime()* DateUnit.MINUTE.getMillis();
                    // 4
                    if(offClock.getOffClockAt() > preClockParam.getClasseEndAt() + overtimeConfig.getRestTime() * DateUnit.MINUTE.getMillis()){
                        end = offClock.getOffClockAt();
                    }
                }
                // 4
                else {
                    start = offClock.getOnClockAt();
                    // 4
                    end = offClock.getOffClockAt();
                }
            }
            //  都不休息
            // 每个区间对应的数字
            //    |_________________________|
            //  1              2             3
            else {
                // 1
                if (offClock.getOnClockAt() <= preClockParam.getClasseStartAt()) {
                    start = preClockParam.getClasseStartAt();
                }
                // 2 3
                else {
                    start = offClock.getOnClockAt();

                }
                // 4
                end = offClock.getOffClockAt();
            }

            if(start != null && end != null && end > start){
                overtime = new UserOvertime();
                overtime.setStartAt(start);
                overtime.setEndAt(end);
                overtime.setDeductRestTime(deductRestTime);
                overtime.setOvertime(IUserClockService.getIntervalMinutes(end, start) - deductRestTime);
            }
        }

        return overtime;
    }

    /**
     * 全天工作计加班，下班晚走的情况
     * @param preClockParam
     * @param offClock
     * @param overtimeConfig
     * @return
     */
    private UserOvertime userOvertimeAllDayWork(PreClockParam preClockParam,UserClock offClock,OvertimeConfig overtimeConfig){

        UserOvertime overtime = null;

        // 工作加班，不考虑上班打卡，从班次结束开始
        int deductRestTime = 0;
        if (overtimeConfig.getIsDeductRestTime()){
            deductRestTime = overtimeConfig.getRestTime();
        }
        if (offClock.getOffClockAt() > preClockParam.getClasseEndAt() + deductRestTime * DateUnit.MINUTE.getMillis()) {
            overtime = new UserOvertime();
            overtime.setStartAt(preClockParam.getClasseEndAt());
            overtime.setEndAt(offClock.getOffClockAt());
            overtime.setOvertime(IUserClockService.getIntervalMinutes(offClock.getOffClockAt(), preClockParam.getClasseEndAt() + deductRestTime * DateUnit.MINUTE.getMillis()));
            overtime.setDeductRestTime(deductRestTime);
        }



        return overtime;
    }

    /**
     * 上午休息下午上班（上半个班次休息，下半个班次上班）
     * @param preClockParam
     * @param offClock
     * @param overtimeConfig
     * @return
     */
    private UserOvertime userOvertimeAmRestPmWork(PreClockParam preClockParam,UserClock offClock,OvertimeConfig overtimeConfig){

        return userOvertimeAllDayWork(preClockParam,offClock,overtimeConfig);
    }

    /**
     * 下午休息上午上班（下半个班次休息，上半个班次上班）
     * @param preClockParam
     * @param offClock
     * @param overtimeConfig
     * @return
     */
    private UserOvertime userOvertimeAmWorkPmRest(PreClockParam preClockParam,UserClock offClock,OvertimeConfig overtimeConfig){
        UserOvertime overtime = null;

        Long start = null;
        Long end = null;
        int deductRestTime = 0;
        // 全部包括休息时间
        // 每个区间对应的数字
        //    |_____________|__|____________|__|
        //                   1       2        3      4
        if(preClockParam.getClasse().getIsHasRest() && overtimeConfig.getIsDeductRestTime()){
            start = preClockParam.getClasseRestEndAt();
            // 1
            if(offClock.getOffClockAt() < preClockParam.getClasseRestEndAt()){
            }
            // 2
            else if(offClock.getOffClockAt() < preClockParam.getClasseEndAt()){
                end = offClock.getOffClockAt();
            }
            // 3
            else if(offClock.getOffClockAt() < preClockParam.getClasseEndAt() + overtimeConfig.getRestTime() * DateUnit.MINUTE.getMillis()){
                end =  preClockParam.getClasseEndAt();
            }
            // 4
            else {
                end = offClock.getOffClockAt();
                deductRestTime = overtimeConfig.getRestTime();
            }
        }
        // 班次休息，下班之后不休息
        // 每个区间对应的数字
        //    |_____________|__|____________|
        //                   1       2        3
        else if(preClockParam.getClasse().getIsHasRest() && !overtimeConfig.getIsDeductRestTime()){
            start = preClockParam.getClasseRestEndAt();
            // 1
            if(offClock.getOffClockAt() < preClockParam.getClasseRestEndAt()){
            }
            // 2 3
            else {
                end = offClock.getOffClockAt();
            }
        }
        // 班次不休息，下班之后休息
        // 每个区间对应的数字
        //    |_____________|____________|__|
        //                        1       2     3
        else if(!preClockParam.getClasse().getIsHasRest() && overtimeConfig.getIsDeductRestTime()){
            start = preClockParam.getClasseRestStartAt();
            // 1
            if(offClock.getOffClockAt() < preClockParam.getClasseEndAt()){
                end = offClock.getOffClockAt();
            }
            // 2
            else if(offClock.getOffClockAt() < preClockParam.getClasseEndAt() + overtimeConfig.getRestTime() * DateUnit.MINUTE.getMillis()){
                end = preClockParam.getClasseEndAt();
            }
            // 3
            else {
                end = offClock.getOffClockAt();
                deductRestTime = overtimeConfig.getRestTime();
            }
        }
        //  都不休息
        // 每个区间对应的数字
        //    |_____________|____________|
        //                        1        2
        else {
            start = preClockParam.getClasseRestStartAt();
            end = offClock.getOffClockAt();
        }

        if(start != null && end != null && end > start){
            overtime = new UserOvertime();
            overtime.setStartAt(start);
            overtime.setEndAt(end);
            overtime.setDeductRestTime(deductRestTime);
            overtime.setOvertime(IUserClockService.getIntervalMinutes(end, start) - deductRestTime);
        }
        return overtime;
    }
}
